/*
 * 网上实例：
 * 存在问题，如果一行有空的单元格，移动会出错。还有是，使用不太方便。
 * 但有好处是会判断位置，会显示类似于位置插入线一样的参考线（但不明显）
 */
#include "routetablewidget.h"

#include <QDebug>
#include <QDropEvent>

RouteTableWidget::RouteTableWidget(QWidget *parent)
    : QTableWidget(parent)
{
    setDragEnabled(true);
    setAcceptDrops(true);
    viewport()->setAcceptDrops(true);
    setDragDropOverwriteMode(false);
    setDropIndicatorShown(true);

    setSelectionMode(QAbstractItemView::SingleSelection);
    setSelectionBehavior(QAbstractItemView::SelectRows);
    setDragDropMode(QAbstractItemView::InternalMove);
}

/**/
void RouteTableWidget::dropEvent(QDropEvent *event)
{
    // 限制仅在当前表格内移动
    if((this == event->source())
    && (Qt::MoveAction == event->dropAction()
        || QAbstractItemView::InternalMove == dragDropMode()))
    {
        int row = -1;
        int col = -1;
        QModelIndex topIndex;
        if(dropOn(event, row, col, topIndex))
        {
            QList<int> selRows = getSelectedRowsFast();

            int top = selRows[0];
            qDebug() << "top is" << top;
            int dropRow = row;
            if(dropRow == -1)
            {
                dropRow = rowCount();
            }
            qDebug() << "dropRow is" << dropRow;
            int offset = dropRow - top;
            qDebug() << " offset is" << offset;

            foreach(auto row, selRows)
            {
                int r = row + offset;
                if(r > rowCount() || r < 0)
                {
                    r = 0;
                }
                insertRow(r);
                qDebug() << "inserting row at" << r;
            }

            selRows = getSelectedRowsFast();
            qDebug() << "selected rows:" << selRows;

            top = selRows[0];
            qDebug() << "top is" << top;
            offset = dropRow - top;
            qDebug() << "offset is" << offset;
            foreach(auto row, selRows)
            {
                int r = row + offset;
                if(r > rowCount() || r < 0)
                {
                    r = 0;
                }
                for(int j = 0; j < columnCount(); ++j)
                {
                    qDebug() << "Source is (" << row << "," << j << ")";
                    qDebug() << "item text:" << item(row, j)->text();
                    QTableWidgetItem *source = new QTableWidgetItem(*item(row, j));
                    qDebug() << "dest is (" << r << "," << j << ")";
                    setItem(r, j, source);
                }
            }

            // Why does this NOT need to be here?
            // for row in reversed(selRows):
                // self.removeRow(row)

            event->accept();
        }
    }
    else
    {
        dropEvent(event);
    }
}

QList<int> RouteTableWidget::getSelectedRowsFast()
{
    QList<int> selRows;

    foreach(auto item, selectedItems())
    {
        if(-1 == selRows.indexOf(item->row()))
        {
            selRows.append(item->row());
        }
    }

    return selRows;
}

bool RouteTableWidget::droppingOnItself(QDropEvent *event, QModelIndex &index)
{
    int dropAction = event->dropAction();

    if(QAbstractItemView::InternalMove == dragDropMode())
    {
        dropAction = Qt::MoveAction;
    }

    if((this == event->source())
    && (event->possibleActions() & Qt::MoveAction)
    && dropAction == Qt::MoveAction)
    {
        QModelIndexList selectedIndexes = this->selectedIndexes();
        QModelIndex child = index;
        while(child.isValid() & child != rootIndex())
        {
            if(-1 != selectedIndexes.indexOf(child))
            {
                return true;
            }
            child = child.parent();
        }
    }

    return false;
}

bool RouteTableWidget::dropOn(QDropEvent *event, int &row, int &col, QModelIndex &index)
{
    if(event->isAccepted())
    {
        return false;
    }

    int dropIndicatorPosition;

    qDebug() << "width:" << width();
    qDebug() << "height:" << height();
    qDebug() << "viewport:" << viewport();
    qDebug() << "viewport->rect:" << viewport()->rect();

    if(viewport()->rect().contains(event->pos()))
    {
        index = indexAt(event->pos());
        if((!index.isValid()) || (!visualRect(index).contains(event->pos())))
        {
            index = rootIndex();
        }
    }

    if(model()->supportedDragActions() & event->dropAction())
    {
        if(index != rootIndex())
        {
            dropIndicatorPosition = position(event->pos(), visualRect(index), index);

            if(QAbstractItemView::AboveItem == dropIndicatorPosition)
            {
                row = index.row();
                col = index.column();
                // index = index.parent;
            }
            else if(QAbstractItemView::BelowItem == dropIndicatorPosition)
            {
                row = index.row() + 1;
                col = index.column();
                // index = index.parent()
            }
            else
            {
                row = index.row();
                col = index.column();
            }
        }
        if(!droppingOnItself(event, index))
        {
            qDebug() << "row is" << row;
            qDebug() << "col is" << col;
            return true;
        }
    }

    return false;
}

int RouteTableWidget::position(QPoint pos, QRect rect, QModelIndex &index)
{
    int r = QAbstractItemView::OnViewport;
    int margin = 2;
    if(pos.y() - rect.top() < margin)
    {
        r = QAbstractItemView::AboveItem;
    }
    else if(rect.bottom() - pos.y() < margin)
    {
        r = QAbstractItemView::BelowItem;
    }
    else if(rect.contains(pos, true))
    {
        r = QAbstractItemView::OnItem;
    }

    if(r == QAbstractItemView::OnItem && (model()->flags(index) & Qt::ItemIsDragEnabled))
    {
        r = pos.y() < rect.center().y() ? QAbstractItemView::AboveItem
                                        : QAbstractItemView::BelowItem;
    }

    return r;
}
